<template>
	<div class="video-container">
		<transition name="el-fade-in-linear">
			<div v-if="multiple || fileList.length == 0" class="upload-main">
				<el-upload class="avatar-uploader" action="" :http-request="doUpload" :accept="acceptType" :multiple="multiple" :drag="drag"
				 :auto-upload="autoUpload"  :before-upload="beforeUpload" :on-success="onSuccess" :on-on-error="onError" :on-progress="onProgress"
				 :on-change="onChange"  :show-file-list="false">
					<slot v-if="$slots.default"></slot>
					<el-button v-else type="primary" size="medium">{{buttonName}}</el-button>
					<div slot="tip" class="el-upload__tip">
					</div>
				</el-upload>
				<div class="tip-content" v-if="tipContent">
					{{tipContent}}
				</div>
			</div>
		</transition>
		<transition name="el-fade-in-linear">
			<div v-if="fileList && fileList.length > 0" class="uploading-box"  v-loading="loading" >
				<template v-for="(currentFile,index) in fileList">
					<div class="file-item" @click.stop="checkItem(currentFile)">
						{{currentFile.fileName}}
						<i class="el-icon-circle-check" v-if="currentFile.status == 3" style="color: #67C23A;"></i>
						<i class="el-icon-video-pause operate-i" v-if="currentFile.status == 1" @click.stop="uploadPause(index)"></i>
						<i class="el-icon-video-play operate-i" v-if="currentFile.status == 2" @click.stop="goOnUpload(index)"></i>
						<i class="el-icon-circle-close operate-i" style="color: #F56C6C;" @click.stop="delteFile(index)"></i>
					</div>
					<transition name="el-fade-in-linear">
						<el-progress v-if="currentFile.status == 1 || currentFile.status == 2" :percentage="currentFile.progressNum" ></el-progress>
					</transition>
				</template>
				
			</div>
		</transition>
	</div>
</template>

<script>
	/**
	 * 20M以上 请用分片上传
	 */
	import md5 from 'js-md5'
	import {getUUID} from "@/common/utils.js"
	export default {
		props: {
			that: {
				type: Object,
				default: this
			},
			multiple: {
				type: Boolean,
				default: false
			},
			drag: {
				type: Boolean,
				default: false
			},
			autoUpload: {
				type: Boolean,
				default: true
			},
			buttonName: {
				type: String,
				default: "上传视频"
			},
			tipContent: {
				type: String,
				default: ""
			},
			maxFileSize: {
				// 单位M
				type: Number,
				default: 200
			},
			fileNum: {
				type: Number,
				default: 1
			},
			validate: {
				type: Function,
				default: () => {
					return false;
				}
			},
			defaultFiles: {
				type: Array,
				default: ()=>[]
			},
			uploadParam: {
				type: Object,
				default: () => {}
			},
			isFrag: {
				type: Boolean,
				default: true
			},
			pieceSize: {
				type: Number,
				default: 2 //默认2M
			},
			acceptType:{
				type:String,
				default:"video/*"
			}
		},
		mounted() {
			let _this = this;
			if(_this.defaultFiles && _this.defaultFiles.length > 0){
				_this.defaultFiles.map(el=>{
					el.status = 3;
					el.uid = getUUID(20,10);
					el.url = el.fileUrl;
				})
				_this.fileList = _this.defaultFiles;
			}
		},
		// watch: {
		// 	defaultFiles() {
		// 		debugger
		// 		let _this = this;
		// 		if(_this.defaultFiles && _this.defaultFiles.length > 0){
		// 			_this.defaultFiles.map(el=>{
		// 				el.status = 3;
		// 			})
		// 			_this.fileList = _this.defaultFiles;
		// 		}
		// 	}
		// },
		data() {
			return {
				url: "",
				uploadList: [],
				fileList: [],
				fileUIDList:[],
				/*分片上传*/
				successAllCount: 0, // 上传成功的片数
				currentAllChunk: 0, // 当前上传的片数索引
				AllChunk: 0, // 所有文件的chunk数之和
				AllFileSize: 0, // 所有文件size
				terminateUpload: false,
				loading:false
			}
		},
		methods: {
			doUpload(params) {
				let file = params.file;
				if (this.isFrag) {
					this.doFragUpload(file);
				} else {
					this.doNormal(file)
				}
			},
			async doNormal(file) {
				let _this = this;
				_this.loading = true;
				await _this.readFileMD5(file).then(f=>{
					file = f;
				});
				let fileName = file.name;
				file.fileName = fileName;
				let fileExtension = fileName.substr(fileName.lastIndexOf(".") + 1, fileName.length);
				let formData = new FormData();
				formData.append('fileExtension', fileExtension);
				formData.append('file', file);
				let uploadParam = _this.uploadParam;
				if (uploadParam && JSON.stringify(uploadParam) != "{}") {
					for (pName in uploadParam) {
						formData[pName] = uploadParam[pName];
					}
				}
				let ret = await _this.$api.videoUpload(formData);

				if (ret) {
					file.status = 3;
					let url = ret.data.url;
					_this.uploadList.push(url);
					_this.$emit("onSuccess", ret, file, this.fileList);
					_this.fileList.push(file);
					_this.fileUIDList.push(file.uid);
				}else{
					console.log("上传失败，请重新上传")
				}
				_this.loading = false;
			},
			beforeUpload(file) {
				if (this.validate()) {

				} else {
					const isRightFile = file.type.startsWith("video");
					if (!isRightFile) {
						return false;
					}
					const maxFileSize = this.maxFileSize;
					const isRightSize = Number(file.size) / 1024 / 1024 < maxFileSize;
					if (!isRightSize) {
						return false;
					}
				}
				this.$emit("beforeUpload", file);
				return true;
			},
			onSuccess(response, file, fileList) {
				//文件上传成功时的钩子
				this.$emit("onSuccess", response, file, fileList);
			},
			onError(err, file, fileList) {
				//文件上传失败时的钩子
				this.$emit("onPreview", err, file, fileList);
			},
			onProgress(event, file, fileList) {
				//文件上传时的钩子
				this.$emit("onProgress", event, file, fileList);
			},
			onChange(file, fileList) {
				//文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
				this.$emit("onChange", file, fileList);
			},
			getUploadResult() {
				return {
					url: this.url,
					uploadList: this.uploadList
				}
			},

			/**分片上传*/
			doFragUpload(file) {
				this.loading = true;
				this.successAllCount = 0; // 上传成功的片数
				this.currentAllChunk = 0; // 当前上传的片数索引
				this.AllChunk = 0; // 所有文件的chunk数之和
				this.AllFileSize = 0; // 所有文件size
				this.terminateUpload = false;
				this.initFileList(file);
			},
			// 获取md5
			async initFileList(file) {
				// 读取每个文件的md5
				let _this = this;
				// let fileList = _this.fileList;
				// for(let i = 0; i < fileList.length ; i++){
				// 	let file = fileList[i];
				// 	await this.readFileMD5(file,fileList).then(f =>{
				// 		fileList[i] = f;
				// 	});
				// }
				await this.readFileMD5(file).then(f =>{
					file = f;
				});
				_this.initFileChunk(file);
			},
			readFileMD5(file){
				let _this = this;
				return new Promise((resolve,reject)=>{
					let fileRederInstance = new FileReader()
					fileRederInstance.readAsBinaryString(file);
					fileRederInstance.onload =  function(e) {
						let fileBolb = e.target.result
						let fileMd5 = md5(fileBolb)
						if (!_this.fileList.some((arr) => arr.md5 === fileMd5)) {
							_this.AllFileSize = _this.AllFileSize + file.size
							resolve({
								fileMd5: fileMd5,
								uid:file.uid,
								fileName: file.name,
								file
							})
						}
						
					}
				})
			},
			getChunkInfo(currentFile) {
				//获取分片信息
				let file = currentFile.file;
				let chunkSize = currentFile.chunkSize;
				let start = currentFile.currentChunk * chunkSize
				let end = Math.min(file.size, start + chunkSize)
				let chunk = file.slice(start, end);
				return {
					start,
					end,
					chunk
				}
			},
			initFileChunk(file) {
				// let _this = this;
				// 针对每个文件进行chunk处理
				// console.log(_this.fileList.length);
				// _this.fileList.map((currentFile,fileIndex) =>{
				// 	_this.doFileChunkUpload(fileIndex);
				// }) 
				this.doFileChunkUpload(file);
			},
			async doFileChunkUpload(currentFile){
				let _this = this;
				if(!currentFile.status){
					//初始化文件分片信息
					currentFile.status = 1;//文件上传状态 0未上传 1上传中 2暂停 3成功 4上传失败 5需要删除
					currentFile.progressNum = 0;//文件分片成功个数
					currentFile.chunkSize = _this.pieceSize * 1024 * 1024; 
					currentFile.chunkCount = Math.ceil(currentFile.file.size / currentFile.chunkSize); // 总片数
					currentFile.currentChunk = 0;
					_this.fileList.push(currentFile);
					_this.fileUIDList.push(currentFile.uid);
					_this.$set(_this.fileList,_this.fileUIDList.indexOf(currentFile.uid),currentFile);//更新数组 手动 因为自己不渲染
				}
				_this.AllChunk = _this.AllChunk + currentFile.chunkCount // 计算全局chunk数
				// let fileSize = currentFile.file.size // 文件大小
				// 针对单个文件进行chunk上传
				while(currentFile.currentChunk < currentFile.chunkCount) {
					
					//监听停止上传
					_this.$on("endUpload",(fmd5,status)=>{
						if(fmd5 == currentFile.fileMd5){
							currentFile.status = status;
						}
					})
					//如果暂停了跳出循环
					if(currentFile.status == 2 || currentFile.status == 5){
						//暂停
						break;
					}
					if (currentFile.chunkErrorCunt >= 3) {
						//如果上传次数大于3次则说明接口有问题 终止上传
						currentFile.status = 4;
						console.log("上传失败次数大于3次")
						let fIndex = _this.fileUIDList.indexOf(currentFile.uid);
						_this.fileUIDList.splice(fIndex,1);
						_this.fileList.splice(fIndex,1);
						break;
					}
					const {chunk} = _this.getChunkInfo(currentFile);
					try{
						await _this.readChunkMD5(currentFile, chunk).then(res => {
							if(res.errCode == 90040015){
								console.log(res)
								throw new Error(res.message);
							}
							//上传成功后都有一个id
							if (currentFile.currentChunk == res.currentChunk) {
								//上传后的分片索引如果等于当前索引，则说明当前上传失败
								currentFile.chunkErrorCunt++;
							} else {
								currentFile.id = res.data.id;
								currentFile.chunkErrorCunt = 0;
								currentFile.currentChunk = res.currentChunk;
							}
							_this.successAllCount = currentFile.currentChunk ;//总上传成功片数
							currentFile.progressNum = Math.ceil(currentFile.currentChunk / currentFile.chunkCount * 100);//上传进度
							this.$set(_this.fileList,_this.fileUIDList.indexOf(currentFile.uid),currentFile);//更新数组 手动 因为自己不渲染
							if (currentFile.currentChunk == currentFile.chunkCount) {
								//单个文件上传成功
								let url = res.data.fileUrl;
								if (!_this.uploadList.includes(url)) {
									_this.uploadList.push(url);
								}
								currentFile.url = url;
								setTimeout(()=>{
									currentFile.status = 3;
									this.$set(_this.fileList,_this.fileUIDList.indexOf(currentFile.uid),currentFile);//更新数组 手动 因为自己不渲染
								},500)
								
								_this.$emit("onSuccess", res, currentFile.file,  this.fileList);
							}
							switch (currentFile.status){
								case 5:
									_this.deleteFileToServer(currentFile);
									break;
								case 2:
								case 1:
								default:
									_this.loading = false;
									break;
							}
						})
					}catch(e){
						//捕获异常后还原
						let index = _this.fileUIDList.indexOf(currentFile.uid);
						_this.fileList.splice(index,1)
						_this.fileUIDList.splice(index,1);
						break;
					}
					
				}
			},
			readChunkMD5(currentFile, chunk) {
				let _this = this;
				//读取分片MD5信息
				return new Promise((resolve, reject) => {
					let chunkFR = new FileReader();
					chunkFR.readAsBinaryString(chunk);
					chunkFR.onload = async function(e) {
						let chunkBolb = e.target.result
						let chunkMD5 = md5(chunkBolb)
						let res = await _this.uploadChunk(currentFile, {
							chunkMD5,
							chunk,
							currentChunk: currentFile.currentChunk,
							chunkCount:currentFile.chunkCount
						});
						resolve(res);
					}
				})
			},
			async uploadChunk(currentFile, chunkInfo) {
				let _this = this;
				let fetchForm = new FormData()
				fetchForm.append('fileSizeTotal', currentFile.file.size)
				fetchForm.append('fileName', currentFile.fileName)
				fetchForm.append('fileMd5', currentFile.fileMd5)
				fetchForm.append('file', chunkInfo.chunk)
				fetchForm.append('slicesNum', chunkInfo.chunkCount)
				fetchForm.append('slicesId', chunkInfo.currentChunk)
				return await this.$api.videoSlicesUpload(fetchForm).then(res => {
					let currentChunk = 0;
					if (Number(res.errCode) == 0 && res.data) {
						let slicesIds = res.data.slicesIds; //已上传的索引
						let ids = slicesIds.split(",");
						currentChunk = Number(ids[ids.length - 1]);
					}
					res.currentChunk = currentChunk + 1;
					
					return res
					
				}).catch((e) => {
					console.log(e)
					return {
						currentChunk: chunkInfo.currentChunk
					};
				})
			},
			uploadPause(index) {
				this.loading = true;
				this.$emit("endUpload", this.fileList[index].fileMd5,2);
			},
			goOnUpload(index){
				this.loading = true;
				this.fileList[index].status = 1;
				this.doFileChunkUpload(this.fileList[index],index);
			},
			delteFile(index){
				this.loading = true;
				let currentFile = this.fileList[index];
				if(currentFile.status == 2 || currentFile.status == 3 || currentFile.status == 4){
					this.deleteFileToServer(currentFile);
				}else{
					this.$emit("endUpload", this.fileList[index].fileMd5,5);
				}
			},
			async deleteFileToServer(currentFile){
				let url = currentFile.url;
				if(this.isFrag){
					let id = currentFile.id;
					await this.$api.deleteSliceFile(id);
				}else{
					this.$api.fileDelete([url]);
				}
				let index = this.fileUIDList.indexOf(currentFile.uid);
				this.fileList.splice(index,1);
				this.fileUIDList.splice(index,1)
				if(url){
					this.uploadList.splice(this.uploadList.indexOf(url),1);
				}
				this.loading = false;
			},
			checkItem(currentFile){
				if(currentFile.status == 3){
					this.$emit("checkItem", currentFile);
				}
			},
			getFileList(){
				let fileList = this.fileList;
				if(fileList.length == 0){
					return null;
				}
				for(let i = 0; i < fileList.length ; i++){
					if(fileList[i].status != 3){
						return null;
					}
				}
				
				return fileList;
			}
			
		}
	}
</script>

<style lang="scss" scoped="scoped">
	.video-container {
		.uploading-box{
			.file-item{
				padding-left: 16px;
				cursor: pointer;
				
				i{
					font-size: 14px;
					margin-left: 8px;
				}
			}
			.file-item:hover{
				background-color: #F5F7FA;
				color: #409EFF;
			}
			.operate-i:hover{
				color: #409EFF !important;
			}
		}
		.upload-main{
			display: flex;
			flex-direction: row;
			align-items: center;
			
			.tip-content{
				margin-left: 16px;
				color: #B2B2B2;
			}
		}
	
		
	}

	::v-deep.el-form-item__content {
		.avatar-uploader {
			display: flex;
			flex-direction: row;

			.lx-upload-button {
				display: flex;
				flex-direction: column;
				justify-content: center;
				align-items: center;
			}

			.el-upload {
				border-radius: 6px;
				cursor: pointer;
				position: relative;
				overflow: hidden;
				float: left;
				line-height: 14px;
				background-color: #F7F8FA;
				display: flex;
				flex-direction: column;
				justify-content: center;
				border: none;

				.avatar-uploader-icon {
					font-size: 30px;
					color: #DADEE1;
					margin-bottom: 16px;
				}

				.avatar-uploader-text {
					color: #999999;
					font-size: 14px;
				}

				.avatar {

					.el-image__inner {}
				}
			}

			.el-upload__tip {
				width: 0;
				flex: 1;
				font-size: 14px;
				display: flex;
				padding-left: 16px;
				color: #B2B2B2;
				flex-direction: column;
				justify-content: flex-end;
				line-height: 20px;
			}
		}

	}
</style>
